package com.carey.blog.jsonrpc.impl;

import static com.carey.blog.model.BlogSync.BLOG_SYNC_EXTERNAL_ARCHIVE_DATE;
import static com.carey.blog.model.BlogSync.BLOG_SYNC_EXTERNAL_ARCHIVE_DATES;
import static com.carey.blog.model.BlogSync.BLOG_SYNC_EXTERNAL_ARTICLES;
import static com.carey.blog.model.BlogSync.BLOG_SYNC_EXTERNAL_ARTICLE_ABSTRACT;
import static com.carey.blog.model.BlogSync.BLOG_SYNC_EXTERNAL_ARTICLE_CATEGORIES;
import static com.carey.blog.model.BlogSync.BLOG_SYNC_EXTERNAL_ARTICLE_CONTENT;
import static com.carey.blog.model.BlogSync.BLOG_SYNC_EXTERNAL_ARTICLE_CREATE_DATE;
import static com.carey.blog.model.BlogSync.BLOG_SYNC_EXTERNAL_ARTICLE_ID;
import static com.carey.blog.model.BlogSync.BLOG_SYNC_EXTERNAL_ARTICLE_IMPORTED;
import static com.carey.blog.model.BlogSync.BLOG_SYNC_EXTERNAL_ARTICLE_TITLE;
import static com.carey.blog.model.BlogSync.BLOG_SYNC_EXTERNAL_BLOGGING_SYS;
import static com.carey.blog.model.BlogSync.BLOG_SYNC_EXTERNAL_BLOGGING_SYS_USER_NAME;
import static com.carey.blog.model.BlogSync.BLOG_SYNC_EXTERNAL_BLOGGING_SYS_USER_PASSWORD;
import static com.carey.blog.model.BlogSync.BLOG_SYNC_IMPORTED;
import static com.carey.blog.model.BlogSync.BLOG_SYNC_MGMT_ADD_ENABLED;
import static com.carey.blog.model.BlogSync.BLOG_SYNC_MGMT_REMOVE_ENABLED;
import static com.carey.blog.model.BlogSync.BLOG_SYNC_MGMT_UPDATE_ENABLED;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import com.carey.blog.action.StatusCodes;
import com.carey.blog.framework.latke.Keys;
import com.carey.blog.framework.latke.action.ActionException;
import com.carey.blog.framework.latke.action.util.PageCaches;
import com.carey.blog.framework.latke.model.User;
import com.carey.blog.framework.latke.repository.Transaction;
import com.carey.blog.jsonrpc.AbstractGAEJSONRpcService;
import com.carey.blog.listener.CareyBlogServletListener;
import com.carey.blog.model.Article;
import com.carey.blog.repository.ArticleRepository;
import com.carey.blog.repository.BlogSyncManagementRepository;
import com.carey.blog.repository.ExternalArticleSoloArticleRepository;
import com.carey.blog.repository.impl.ArticleGAERepository;
import com.carey.blog.repository.impl.BlogSyncMgmtGAERepository;
import com.carey.blog.repository.impl.ExternalArticleSoloArticleGAERepository;
import com.carey.blog.sync.BlogFactory;
import com.carey.blog.sync.MetaWeblog;
import com.carey.blog.sync.Post;
import com.carey.blog.util.ArchiveDates;
import com.carey.blog.util.Articles;
import com.carey.blog.util.Statistics;
import com.carey.blog.util.Tags;
import com.carey.blog.util.Users;

/**
 * Blog sync service for JavaScript client.
 * 
 */
public final class BlogSyncService extends AbstractGAEJSONRpcService {

	/**
	 * Logger.
	 */
	private static final Logger LOGGER = Logger.getLogger(BlogSyncService.class
			.getName());
	/**
	 * Article repository.
	 */
	private ArticleRepository articleRepository = ArticleGAERepository
			.getInstance();
	/**
	 * Tag utilities.
	 */
	private Tags tagUtils = Tags.getInstance();
	/**
	 * Article utilities.
	 */
	private Articles articleUtils = Articles.getInstance();
	/**
	 * Statistic utilities.
	 */
	private Statistics statistics = Statistics.getInstance();
	/**
	 * Archive date utilities.
	 */
	private ArchiveDates archiveDateUtils = ArchiveDates.getInstance();
	/**
	 * External blog article-Solo article repository.
	 */
	private ExternalArticleSoloArticleRepository externalArticleSoloArticleRepository = ExternalArticleSoloArticleGAERepository
			.getInstance();
	/**
	 * Blog sync management repository.
	 */
	private BlogSyncManagementRepository blogSyncManagementRepository = BlogSyncMgmtGAERepository
			.getInstance();
	/**
	 * User utilities.
	 */
	private Users userUtils = Users.getInstance();
	/**
	 * External blog article retrieval count incremental.
	 */
	public static final int EXTERNAL_ARTICLE_RETRIEVAL_COUNT_INCREMENTAL = 2;

	/**
	 * Gets blog sync management for external blogging system with the specified
	 * http servlet request and http servlet response.
	 * 
	 * @param requestJSONObject
	 *            the specified request json object, for example,
	 * 
	 *            <pre>
	 * {
	 *     ""blogSyncExternalBloggingSys": ""
	 * }
	 * </pre>
	 * @param request
	 *            the specified http servlet request
	 * @param response
	 *            the specified http servlet response
	 * @return for example,
	 * 
	 *         <pre>
	 * {
	 *     "blogSyncExternalBloggingSys": "",
	 *     "blogSyncExternalBloggingSysUserName": "",
	 *     "blogSyncExternalBloggingSysUserPassword": "",
	 *     "blogSyncMgmtAddEnabled": boolean,
	 *     "blogSyncMgmtUpdateEnabled": boolean,
	 *     "blogSyncMgmtRemoveEnabled": boolean
	 * }, returns {@code null} if not found
	 * </pre>
	 * @throws ActionException
	 *             action exception
	 * @throws IOException
	 *             io exception
	 */
	public JSONObject getBlogSyncMgmt(final JSONObject requestJSONObject,
			final HttpServletRequest request, final HttpServletResponse response)
			throws ActionException, IOException {
		final JSONObject ret = new JSONObject();
		if (!userUtils.isAdminLoggedIn()) {
			response.sendError(HttpServletResponse.SC_FORBIDDEN);
			return ret;
		}

		String externalSys = null;
		try {
			externalSys = requestJSONObject
					.getString(BLOG_SYNC_EXTERNAL_BLOGGING_SYS);
			return blogSyncManagementRepository
					.getByExternalBloggingSystem(externalSys);
		} catch (final JSONException e) {
			LOGGER.log(Level.SEVERE, e.getMessage(), e);
		}

		return null;
	}

	/**
	 * Sets blog sync management for external blogging system with the specified
	 * request json object, http servlet request and http servlet response.
	 * 
	 * @param requestJSONObject
	 *            the specified request json object, for example,
	 * 
	 *            <pre>
	 * {
	 *     ""blogSyncExternalBloggingSys": "",
	 *     "blogSyncExternalBloggingSysUserName": "",
	 *     "blogSyncExternalBloggingSysUserPassword": "",
	 *     "blogSyncMgmtAddEnabled": boolean,
	 *     "blogSyncMgmtUpdateEnabled": boolean,
	 *     "blogSyncMgmtRemoveEnabled": boolean
	 * }
	 * </pre>
	 * @param request
	 *            the specified http servlet request
	 * @param response
	 *            the specified http servlet response
	 * @return for example,
	 * 
	 *         <pre>
	 * {
	 *     "sc": SET_BLOG_SYNC_MGMT_SUCC
	 * }
	 * </pre>
	 * @throws ActionException
	 *             action exception
	 * @throws IOException
	 *             io exception
	 */
	public JSONObject setBlogSyncMgmt(final JSONObject requestJSONObject,
			final HttpServletRequest request, final HttpServletResponse response)
			throws ActionException, IOException {
		final JSONObject ret = new JSONObject();
		if (!userUtils.isAdminLoggedIn()) {
			response.sendError(HttpServletResponse.SC_FORBIDDEN);
			return ret;
		}
		final Transaction transaction = blogSyncManagementRepository
				.beginTransaction();
		try {
			final String externalBloggingSys = requestJSONObject
					.getString(BLOG_SYNC_EXTERNAL_BLOGGING_SYS);
			final String userName = requestJSONObject
					.getString(BLOG_SYNC_EXTERNAL_BLOGGING_SYS_USER_NAME);
			final String userPwd = requestJSONObject
					.getString(BLOG_SYNC_EXTERNAL_BLOGGING_SYS_USER_PASSWORD);
			final boolean addEnabled = requestJSONObject
					.getBoolean(BLOG_SYNC_MGMT_ADD_ENABLED);
			final boolean updateEnabled = requestJSONObject
					.getBoolean(BLOG_SYNC_MGMT_UPDATE_ENABLED);
			final boolean removeEnabled = requestJSONObject
					.getBoolean(BLOG_SYNC_MGMT_REMOVE_ENABLED);

			JSONObject blogSyncMgmt = blogSyncManagementRepository
					.getByExternalBloggingSystem(externalBloggingSys);
			if (null == blogSyncMgmt) {
				blogSyncMgmt = new JSONObject();
			}

			blogSyncMgmt.put(BLOG_SYNC_EXTERNAL_BLOGGING_SYS,
					externalBloggingSys);
			blogSyncMgmt.put(BLOG_SYNC_EXTERNAL_BLOGGING_SYS_USER_NAME,
					userName);
			blogSyncMgmt.put(BLOG_SYNC_EXTERNAL_BLOGGING_SYS_USER_PASSWORD,
					userPwd);
			blogSyncMgmt.put(BLOG_SYNC_MGMT_ADD_ENABLED, addEnabled);
			blogSyncMgmt.put(BLOG_SYNC_MGMT_UPDATE_ENABLED, updateEnabled);
			blogSyncMgmt.put(BLOG_SYNC_MGMT_REMOVE_ENABLED, removeEnabled);

			if (!blogSyncMgmt.has(Keys.OBJECT_ID)) {
				blogSyncManagementRepository.add(blogSyncMgmt);
				LOGGER.log(
						Level.FINER,
						"Added blog sync management for [{0}] [{1}]",
						new String[] {
								externalBloggingSys,
								blogSyncMgmt
										.toString(CareyBlogServletListener.JSON_PRINT_INDENT_FACTOR) });

			} else {
				blogSyncManagementRepository.update(
						blogSyncMgmt.getString(Keys.OBJECT_ID), blogSyncMgmt);
				LOGGER.log(
						Level.FINER,
						"Updated blog sync management for [{0}] [{1}]",
						new String[] {
								externalBloggingSys,
								blogSyncMgmt
										.toString(CareyBlogServletListener.JSON_PRINT_INDENT_FACTOR) });
			}

			transaction.commit();
			ret.put(Keys.STATUS_CODE, StatusCodes.SET_BLOG_SYNC_MGMT_SUCC);
		} catch (final Exception e) {
			if (transaction.isActive()) {
				transaction.rollback();
			}
			LOGGER.log(Level.SEVERE, e.getMessage(), e);
			throw new ActionException(e);
		}

		return ret;
	}

	/**
	 * Imports external blogging system articles by the specified request json
	 * object and http servlet request.
	 * 
	 * @param requestJSONObject
	 *            the specified request json object, for example,
	 * 
	 *            <pre>
	 * {
	 *     "blogSyncExternalBloggingSys": "",
	 *     "oIds": ["", "", ....]
	 * }
	 * </pre>
	 * @param request
	 *            the specified http servlet request
	 * @param response
	 *            the specified http servlet response
	 * @return imported article ids, for example,
	 * 
	 *         <pre>
	 * {
	 *     "oIds": ["", "", ....]
	 * }
	 * </pre>
	 * @throws ActionException
	 *             action exception
	 * @throws IOException
	 *             io exception
	 */
	public JSONObject importExternalArticles(
			final JSONObject requestJSONObject,
			final HttpServletRequest request, final HttpServletResponse response)
			throws ActionException, IOException {
		final JSONObject ret = new JSONObject();
		if (!userUtils.isAdminLoggedIn()) {
			response.sendError(HttpServletResponse.SC_FORBIDDEN);
			return ret;
		}

		try {
			final String blogSyncExternalBloggingSys = requestJSONObject
					.getString(BLOG_SYNC_EXTERNAL_BLOGGING_SYS);
			final JSONArray articleIds = requestJSONObject
					.getJSONArray(Keys.OBJECT_IDS);
			final List<String> importedIds = new ArrayList<String>();
			for (int i = 0; i < articleIds.length(); i++) {
				final Transaction transaction = articleRepository
						.beginTransaction();
				try {
					final String oId = articleIds.getString(i);
					final JSONObject externalArticle = externalArticleSoloArticleRepository
							.getBySoloArticleId(oId,
									blogSyncExternalBloggingSys);
					externalArticle.put(BLOG_SYNC_EXTERNAL_ARTICLE_IMPORTED,
							true);
					externalArticleSoloArticleRepository.update(
							externalArticle.getString(Keys.OBJECT_ID),
							externalArticle);
					final JSONObject soloArticle = toSoloArticle(externalArticle);

					final String categoriesString = externalArticle
							.getString(BLOG_SYNC_EXTERNAL_ARTICLE_CATEGORIES);
					final String[] tagTitles = categoriesString.split(",");
					final JSONArray tags = tagUtils.tag(tagTitles, soloArticle);
					articleUtils.addTagArticleRelation(tags, soloArticle);

					articleRepository.importArticle(soloArticle);
					importedIds.add(oId);

					statistics.incBlogArticleCount();
					statistics.incPublishedBlogArticleCount();

					archiveDateUtils.archiveDate(soloArticle);

					transaction.commit();
				} catch (final Exception e) {
					LOGGER.log(Level.SEVERE, e.getMessage(), e);
					if (transaction.isActive()) {
						transaction.rollback();
					}
				}
			}

			PageCaches.removeAll();
			ret.put(Keys.OBJECT_IDS, importedIds);
		} catch (final JSONException e) {
			LOGGER.log(Level.SEVERE, e.getMessage(), e);
			throw new ActionException(e);
		}

		return ret;
	}

	/**
	 * Gest external blogging system articles by the specified request json
	 * object.
	 * 
	 * @param requestJSONObject
	 *            the specified request json object, for example,
	 * 
	 *            <pre>
	 * {
	 *     "blogSyncExternalBloggingSys": "",
	 *     "blogSyncExternalBloggingSysUserName": "",
	 *     "blogSyncExternalBloggingSysUserPassword": "",
	 *     "blogSyncExternalArchiveDate": "2006/12"
	 * }
	 * </pre>
	 * @param request
	 *            the specified http servlet request
	 * @param response
	 *            the specified http servlet response
	 * @return for example,
	 * 
	 *         <pre>
	 * {
	 *     "blogSyncExternalArticles": [{
	 *         "oId": "",
	 *         "blogSyncExternalArticleTitle": "",
	 *         "blogSyncExternalArticleCreateDate": java.util.Date,
	 *         "blogSyncExternalArticleCategories": "category1, category2, ....",
	 *         "blogSyncExternalArticleContent": "",
	 *         "blogsyncExternalArticleAbstract": ""
	 *     }, ....]
	 * }
	 * </pre>
	 * @throws ActionException
	 *             action exception
	 * @throws IOException
	 *             io exception
	 */
	public JSONObject getExternalArticlesByArchiveDate(
			final JSONObject requestJSONObject,
			final HttpServletRequest request, final HttpServletResponse response)
			throws ActionException, IOException {
		final JSONObject ret = new JSONObject();
		if (!userUtils.isAdminLoggedIn()) {
			response.sendError(HttpServletResponse.SC_FORBIDDEN);
			return ret;
		}

		final Transaction transaction = externalArticleSoloArticleRepository
				.beginTransaction();

		try {
			final String externalSys = requestJSONObject
					.getString(BLOG_SYNC_EXTERNAL_BLOGGING_SYS);
			final String userName = requestJSONObject
					.getString(BLOG_SYNC_EXTERNAL_BLOGGING_SYS_USER_NAME);
			final String userPwd = requestJSONObject
					.getString(BLOG_SYNC_EXTERNAL_BLOGGING_SYS_USER_PASSWORD);
			final String archiveDate = requestJSONObject
					.getString(BLOG_SYNC_EXTERNAL_ARCHIVE_DATE);
			final MetaWeblog metaWeblog = BlogFactory
					.getMetaWeblog(externalSys);
			metaWeblog.setUserName(userName);
			metaWeblog.setUserPassword(userPwd);
			final List<String> externalArticleIds = metaWeblog
					.getArticleIdsByArchiveDate(archiveDate);
			LOGGER.log(
					Level.FINER,
					"There are [{0}] articles of [{1}] user[userName={2}] in [{3}]",
					new Object[] { externalArticleIds.size(), externalSys,
							userName, archiveDate });
			final JSONArray articles = new JSONArray();
			ret.put(BLOG_SYNC_EXTERNAL_ARTICLES, articles);
			int retrievalCnt = 0;
			for (final String externalArticleId : externalArticleIds) {
				final JSONObject soloArticle = externalArticleSoloArticleRepository
						.getSoloArticle(externalArticleId, externalSys);
				JSONObject article = null;
				boolean imported = false;
				if (null != soloArticle) {
					article = soloArticle;
					imported = soloArticle
							.getBoolean(BLOG_SYNC_EXTERNAL_ARTICLE_IMPORTED);
				} else { // Not retrieved yet, get the article from External
							// blogging system
					final Post externalPost = metaWeblog
							.getPost(externalArticleId);
					if (null == externalPost) {
						LOGGER.log(
								Level.WARNING,
								"Retrieve article[postId={0}] from external blogging system[{1}] is null",
								new String[] { externalArticleId, externalSys });
						continue;
					}

					article = externalPost.toJSONObject();
					final JSONObject externalArticleSoloArticleRelation = new JSONObject();
					externalArticleSoloArticleRelation.put(
							BLOG_SYNC_EXTERNAL_ARTICLE_IMPORTED, false);
					externalArticleSoloArticleRelation.put(
							BLOG_SYNC_EXTERNAL_ARTICLE_ID, externalArticleId);
					externalArticleSoloArticleRelation.put(Article.ARTICLE
							+ "_" + Keys.OBJECT_ID,
							article.getString(Keys.OBJECT_ID));
					externalArticleSoloArticleRelation.put(
							BLOG_SYNC_EXTERNAL_BLOGGING_SYS, externalSys);

					externalArticleSoloArticleRelation
							.put(BLOG_SYNC_EXTERNAL_ARTICLE_ABSTRACT,
									article.getString(BLOG_SYNC_EXTERNAL_ARTICLE_ABSTRACT));
					externalArticleSoloArticleRelation
							.put(BLOG_SYNC_EXTERNAL_ARTICLE_CATEGORIES,
									article.getString(BLOG_SYNC_EXTERNAL_ARTICLE_CATEGORIES));
					externalArticleSoloArticleRelation
							.put(BLOG_SYNC_EXTERNAL_ARTICLE_CONTENT,
									article.getString(BLOG_SYNC_EXTERNAL_ARTICLE_CONTENT));
					externalArticleSoloArticleRelation
							.put(BLOG_SYNC_EXTERNAL_ARTICLE_CREATE_DATE,
									article.get(BLOG_SYNC_EXTERNAL_ARTICLE_CREATE_DATE));
					externalArticleSoloArticleRelation
							.put(BLOG_SYNC_EXTERNAL_ARTICLE_TITLE,
									article.getString(BLOG_SYNC_EXTERNAL_ARTICLE_TITLE));

					externalArticleSoloArticleRepository
							.add(externalArticleSoloArticleRelation);
					LOGGER.log(Level.INFO,
							"Saved a external article into tmp repository");
					LOGGER.log(
							Level.FINEST,
							"The external article[relation={0}]",
							externalArticleSoloArticleRelation
									.toString(CareyBlogServletListener.JSON_PRINT_INDENT_FACTOR));

					retrievalCnt++;
				}

				article.put(BLOG_SYNC_IMPORTED, imported);
				articles.put(article);

				if (EXTERNAL_ARTICLE_RETRIEVAL_COUNT_INCREMENTAL == retrievalCnt) {
					break;
				}
			}

			transaction.commit();
		} catch (final Exception e) {
			if (transaction.isActive()) {
				transaction.rollback();
			}
			LOGGER.log(Level.SEVERE, e.getMessage(), e);
			throw new ActionException(e);
		}

		return ret;
	}

	/**
	 * Gets external blogging system article archive dates by the specified
	 * request json object.
	 * 
	 * @param requestJSONObject
	 *            the specified request json object, for example,
	 * 
	 *            <pre>
	 * {
	 *     "blogSyncExternalBloggingSys": "",
	 *     "blogSyncExternalBloggingSysUserName": ""
	 * }
	 * </pre>
	 * @param request
	 *            the specified http servlet request
	 * @param response
	 *            the specified http servlet response
	 * @return for example,
	 * 
	 *         <pre>
	 * {
	 *     "blogSyncExternalArchiveDates": ["2006/12", "2007/01", ...]
	 * }
	 * </pre>
	 * @throws ActionException
	 *             action exception
	 * @throws IOException
	 *             io exception
	 */
	public JSONObject getExternalArticleArchiveDate(
			final JSONObject requestJSONObject,
			final HttpServletRequest request, final HttpServletResponse response)
			throws ActionException, IOException {
		final JSONObject ret = new JSONObject();
		if (!userUtils.isAdminLoggedIn()) {
			response.sendError(HttpServletResponse.SC_FORBIDDEN);
			return ret;
		}

		try {
			final String externalSys = requestJSONObject
					.getString(BLOG_SYNC_EXTERNAL_BLOGGING_SYS);
			final String userName = requestJSONObject
					.getString(BLOG_SYNC_EXTERNAL_BLOGGING_SYS_USER_NAME);
			final MetaWeblog metaWeblog = BlogFactory
					.getMetaWeblog(externalSys);
			metaWeblog.setUserName(userName);
			metaWeblog.setUserPassword("ignored");
			final List<String> archiveDates = metaWeblog.getArchiveDates();

			ret.put(BLOG_SYNC_EXTERNAL_ARCHIVE_DATES, archiveDates);
		} catch (final JSONException e) {
			LOGGER.log(Level.SEVERE, e.getMessage(), e);
			throw new ActionException(e);
		}

		return ret;
	}

	/**
	 * To Carey Blog article(Key transformation) for the specified external blog
	 * article.
	 * 
	 * @param externalArticle
	 *            the specified external Blog article
	 * @return Solo article
	 * @throws Exception
	 *             exception
	 */
	private JSONObject toSoloArticle(final JSONObject externalArticle)
			throws Exception {
		final JSONObject ret = new JSONObject();
		final String articleId = externalArticle.getString(Article.ARTICLE
				+ "_" + Keys.OBJECT_ID);
		ret.put(Keys.OBJECT_ID, articleId);
		ret.put(Article.ARTICLE_TITLE,
				externalArticle.getString(BLOG_SYNC_EXTERNAL_ARTICLE_TITLE));
		ret.put(Article.ARTICLE_ABSTRACT,
				externalArticle.getString(BLOG_SYNC_EXTERNAL_ARTICLE_ABSTRACT));
		ret.put(Article.ARTICLE_CONTENT,
				externalArticle.getString(BLOG_SYNC_EXTERNAL_ARTICLE_CONTENT));
		final Date createDate = (Date) externalArticle
				.get(BLOG_SYNC_EXTERNAL_ARTICLE_CREATE_DATE);
		ret.put(Article.ARTICLE_CREATE_DATE, createDate);
		ret.put(Article.ARTICLE_UPDATE_DATE, createDate);
		ret.put(Article.ARTICLE_TAGS_REF, externalArticle
				.getString(BLOG_SYNC_EXTERNAL_ARTICLE_CATEGORIES));

		ret.put(Article.ARTICLE_VIEW_COUNT, 0);
		ret.put(Article.ARTICLE_COMMENT_COUNT, 0);
		final String permalinkDate = ArticleService.PERMALINK_FORMAT
				.format(createDate);
		final String permalink = "/articles/" + permalinkDate + "/" + articleId
				+ ".html";
		ret.put(Article.ARTICLE_PERMALINK, permalink);
		ret.put(Article.ARTICLE_PUT_TOP, false);
		ret.put(Article.ARTICLE_IS_PUBLISHED, true);
		ret.put(Article.ARTICLE_HAD_BEEN_PUBLISHED, true);
		final JSONObject currentUser = userUtils.getCurrentUser();
		final String currentUserEmail = currentUser.getString(User.USER_EMAIL);
		ret.put(Article.ARTICLE_AUTHOR_EMAIL, currentUserEmail);

		return ret;
	}

	/**
	 * Gets the {@link BlogSyncService} singleton.
	 * 
	 * @return the singleton
	 */
	public static BlogSyncService getInstance() {
		return SingletonHolder.SINGLETON;
	}

	/**
	 * Private default constructor.
	 */
	private BlogSyncService() {
	}

	/**
	 * Singleton holder.
	 * 
	 */
	private static final class SingletonHolder {

		/**
		 * Singleton.
		 */
		private static final BlogSyncService SINGLETON = new BlogSyncService();

		/**
		 * Private default constructor.
		 */
		private SingletonHolder() {
		}
	}
}
